package com.yeziji.devops.config;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.yeziji.common.CommonDataSourceConfig;
import com.yeziji.devops.common.JdbcFillHandler;
import com.yeziji.devops.sql.constructor.InsertSqlConstructor;
import com.yeziji.devops.sql.constructor.UpdateSqlConstructor;
import com.yeziji.utils.expansion.Lists2;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.sql.DataSource;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 基本配置属性
 *
 * @author hwy
 * @since 2024/08/01 17:45
 **/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "yzj.devops")
public class ConfigProperties implements JdbcFillHandler {
    /**
     * 是否打印日志
     */
    private boolean log = true;

    /**
     * 读取配置文件
     */
    private String path;

    /**
     * 动态 api 前缀
     */
    private String apiPrefix = "yzj-devops";

    /**
     * 是否启用
     */
    private Boolean enabled = false;

    /**
     * 创建日期字段
     */
    private String createDate;

    /**
     * 更新日期字段
     */
    private String updateDate;

    /**
     * devops mysql 数据源配置
     */
    private Map<String, DevopsDataSourceProperty> mysql;

    @Override
    public void insertFill(InsertSqlConstructor insertSqlConstructor) {
        String dateColumn = null;
        if (StrUtil.isNotBlank(insertSqlConstructor.getGenDate())) {
            dateColumn = insertSqlConstructor.getGenDate();
        } else if (StrUtil.isNotBlank(this.createDate)) {
            dateColumn = this.createDate;
        }

        // 生成日期，如果 insertSqlConstructor 指定了生成的日期的字段，那么会覆盖配置文件中的 insertDate
        if (dateColumn != null) {
            insertSqlConstructor.getColumns().add(dateColumn);
            List<List<Object>> values = insertSqlConstructor.getValues();
            for (List<Object> value : values) {
                value.add(new Date());
            }
        }
    }

    @Override
    public void updateFill(UpdateSqlConstructor updateSqlConstructor) {
        String dateColumn = null;
        if (StrUtil.isNotBlank(updateSqlConstructor.getGenDate())) {
            dateColumn = updateSqlConstructor.getGenDate();
        } else if (StrUtil.isNotBlank(this.updateDate)) {
            dateColumn = this.updateDate;
        }

        // 生成日期，如果 updateSqlConstructor 指定了生成的日期的字段，那么会覆盖配置文件中的 updateDate
        if (dateColumn != null) {
            Map<String, Object> data = updateSqlConstructor.getData();
            // 补充 update time 数据
            data.put(this.updateDate, new Date());
        }
    }

    @Data
    public static class DevopsDataSourceProperty {
        private static final long serialVersionUID = 7468706035783059491L;

        /**
         * 是否为 devops master 库
         * <p>
         *     如果不是默认为当前项目数据源
         * </p>
         */
        private boolean master;

        /**
         * 数据库驱动名
         */
        private String driverClassName;

        /**
         * 数据库链接
         */
        private String url;

        /**
         * 数据库登录账号
         */
        private String username;

        /**
         * 数据库密码
         */
        private String password;

        /**
         * 连接池配置
         */
        private Map<String, Object> druidParams;
    }


    /**
     * 獲取 devops 指定 master 數據源
     *
     * @return {@link DataSource} 如果沒有在配置指定就返回 null
     */
    public DataSource getMasterDataSource() {
        if (this.mysql == null || this.mysql.isEmpty()) {
            return null;
        }

        // 取第一个 master 为默认数据源
        Optional<DevopsDataSourceProperty> masterDataSourceOpt = Lists2.filterFirstOpt(this.mysql.values(), DevopsDataSourceProperty::isMaster);
        if (masterDataSourceOpt.isPresent()) {
            DevopsDataSourceProperty masterDataSource = masterDataSourceOpt.get();
            DruidDataSource druidDataSource = CommonDataSourceConfig.getInitDruidDataSource();
            druidDataSource.setUrl(masterDataSource.getUrl());
            druidDataSource.setUsername(masterDataSource.getUsername());
            druidDataSource.setPassword(masterDataSource.getPassword());
            druidDataSource.setDriverClassName(masterDataSource.getDriverClassName());
            // 连接池配置
            Map<String, Object> druidParams = masterDataSource.getDruidParams();
            if (MapUtil.isNotEmpty(druidParams)) {
                druidParams.forEach((key, value) -> {
                    Class<? extends DruidDataSource> druidClass = druidDataSource.getClass();
                    try {
                        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(key, druidClass);
                        propertyDescriptor.getWriteMethod().invoke(druidDataSource, value);
                    } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                        // ignored
                    }
                });
            }
            return druidDataSource;
        }
        return null;
    }
}
